/*
 Vue2中，Vue是一个构造函数（类），每一次使用Vue就是创造其一个实例
   let vm = new Vue(options)
   + Vue2采用OptionsAPI的模式：后续开发的内容，会写在options的相关配置项中
      https://v2.cn.vuejs.org/v2/api/ {带“选项/xxx”都是写在options对象中的}

 如何构建数据？
   基于options中的data配置项，来构建“响应式”数据「或者状态」
     + 基本原则：但凡视图中需要动态绑定信息，我们都应该构建相应的数据
     + 在data中构建的数据
       + 都会挂载为实例的私有属性，基于“实例.xxx”即可访问和操作
       + 几乎都做了数据劫持「基于Object.defineProperty做了GET/SET劫持」

 如何构建视图？
   可以基于options对象中的 el/template/render 指定视图容器(或者构建视图)
     + el：指定HTML中的某个容器作为视图
     + template：自己基于<template>模板语法构建视图
     + render：基于JSX语法构建视图
   在Vue.prototype上，可以基于$mount方法指定视图！和配置项中的el非常类似！！

 视图构建一般是基于<template>模板语法：
   + 基于 “{{ }}” 绑定数据「小胡子语法」
     + 在花括号中嵌入“JS表达式”：执行有返回结果的
       例如：数学运算、三元运算符、变量(或状态)、函数执行...
     + 呈现的结果必定是某一种数据类型值
       + 字符串：直接渲染
       + 数字/布尔/BigInt：转换为字符串渲染
       + null/undefined：渲染为空
       + Symbol：直接报错
       + 普通对象/数组对象：基于JSON.stringify把其变为“JSON字符串”进行渲染
       + 正则/日期/函数对象：基于String把其变为字符串渲染
       + ...
   + 挂载到实例上的信息（不论是否是响应式的），可以直接在视图中渲染，无需加this(或实例)
   + 某些特定的全局方法，可以直接在花括号中运行，例如：JSON.stringify/parse、String、Number...，但是window以及其内部的一些属性属性方法是不被支持的！！

 响应式数据（或者状态）：基于defineProperty进行过“数据劫持GET/SET”的数据
   @1 在“new Vue”阶段，写在data中的数据，不仅会挂载到vm实例上，而且默认对这些数据进行“深度”的数据劫持！
      后续基于“vm.xxx=xxx”方式，手动挂载到实例上的数据，是不会进行数据劫持的！！
   @2 可以后续可基于 vm.$set 方法，新增响应式数据
     vm.$set(vm,'num',10)  报错：$set不能直接给vm实例对象设置属性
     vm.$set(vm.obj,'z',30) 给obj状态对象新增z属性，而且z属性还做了数据劫持（响应式数据）；但是有前提：这个属性之前不能存在于对象中，如果之前就有这个属性，此时$set只是在修改值，无法修改其响应式的规则(之前是否为响应式，现在还是相同规则)！
     执行$set方法，不仅可以新增响应式属性(或需改属性值)，而且还会通知视图更新！！
   @3 如果数据值是一个数组，和对象的处理，还是有本质区别的！！
     + 存储数组的属性本身（例如：arr），会被做数据劫持;
     + 但是数组中每个“索引项/length”都没有做数据劫持;
     + Vue内部新建一个原型对象「proto」，在对象中重写了数组的7个方法「例如：push/pop/shift/unshift/splice/sort/reverse」，并且让数组的原型链指向这个原型对象「数组 -> proto -> Array.prototype」；当我么基于这7个方法修改数组中某项值的时候，不仅可以修改值，而且还可以通知视图更新！！
     // vm.arr = [100, 20, 30];  视图可以更新
     // vm.arr[0] = 100;  视图不更新(因为索引项没有做数据劫持)
     // vm.$set(vm.arr, 0, 100);  基于$set在新增(或修改)值的时候，可以通知视图更新
     /!* 
      vm.arr[0] = 100;
      vm.$forceUpdate();   $forceUpdate方法可以控制视图强制更新
     *!/
     // vm.arr.splice(0, 1, 100);  视图可以更新(使用重写的7个方法操作数组，视图就会被通知更新)
     
 响应式状态的最大特点：修改状态值，会触发SET劫持函数，一方面修改值，一方面会自动通知视图进行更新「数据驱动视图渲染的原理」
   + 建议大家在后期的开发中，把需要用到的状态，先在data中声明一下(即便没有值，也先占个位)；这样你所编写的数据都是响应式的，后期修改状态值，视图会更新！！
   + 即便最开始忘记了，也可以基于$set再新增响应式状态！

 控制视图更新的办法：
   + 对于“对象”来讲，只要其属性做了数据劫持，修改属性值，视图就会更新！
   + 对于“数组”来讲，可以基于Vue重写的7个方法进行操作，这样视图也会更新！
   + 可以基于$set方法，在新增(或修改)值的时候，控制视图更新！
   + 可以基于$forceUpdate方法，让视图强制更新！！
   + ...
 */

let vm = new Vue({
    data: {
        msg: 'hello world',
        arr: [10, 20, 30]
    }
});
vm.$mount('#app');
console.log(vm);

setTimeout(() => {
    // vm.arr.splice(0, 1, 100);  视图可以更新(使用重写的7个方法操作数组，视图就会被通知更新)
    // vm.arr = [100, 20, 30];  视图可以更新
    // vm.arr[0] = 100;  视图不更新(因为索引项没有做数据劫持)
    // vm.$set(vm.arr, 0, 100);  基于$set在新增(或修改)值的时候，可以通知视图更新
    /* 
    vm.arr[0] = 100;
    vm.$forceUpdate();   $forceUpdate方法可以控制视图强制更新
    */
}, 2000);


/* let vm = new Vue({
    data: {
        msg: 'hello world',
        obj: {
            x: 10,
            y: 20
        },
        arr: [10, 20, 30]
    }
});
vm.num = 10;
vm.$set(vm.obj, 'z', 30);
vm.$mount('#app');
console.log(vm); */

/* 
// DEMO1
// 响应式数据：msg/obj/obj中的x和y
// 没有数据劫持的：num/obj.z
let vm = new Vue({
    data: {
        msg: 'hello world',
        obj: {
            x: 10,
            y: 20
        }
    }
});
vm.num = 10;
vm.obj.z = 30;
vm.$mount('#app'); 
*/